<template>
  <div class="pf-flow-design pf-bgwhite">
    <div class="pf-flow-design-op">
      <el-button-group key="file-control">
        <el-button :type="'primary'" icon="el-icon-folder-opened" @click="refFileDom.click()"
          >打开文件</el-button
        >
        <el-tooltip effect="light">
          <template v-slot:content>
            <el-button link type="primary" @click="downloadProcess('xml')">下载为XML文件</el-button>
            <br />
            <el-button link type="primary" @click="downloadProcess('svg')">下载为SVG文件</el-button>
            <br />
            <el-button link type="primary" @click="downloadProcess('bpmn')"
              >下载为BPMN文件</el-button
            >
          </template>
          <el-button :type="'primary'" icon="el-icon-download">下载文件</el-button>
        </el-tooltip>
        <el-tooltip effect="light">
          <template v-slot:content>
            <el-button link type="primary" @click="previewProcessXML">预览XML</el-button>
            <br />
            <el-button link type="primary" @click="previewProcessJson">预览JSON</el-button>
          </template>
          <el-button :type="'primary'" icon="el-icon-view">预览</el-button>
        </el-tooltip>
      </el-button-group>
      <el-button-group key="stack-control">
        <el-tooltip effect="light" content="撤销">
          <el-button :disabled="!revocable" icon="Refresh-left" @click="processUndo()" />
        </el-tooltip>
        <el-tooltip effect="light" content="恢复">
          <el-button :disabled="!recoverable" icon="Refresh-right" @click="processRedo()" />
        </el-tooltip>
      </el-button-group>
      <!-- 用于打开本地文件-->
      <input
        type="file"
        id="files"
        ref="refFileDom"
        style="display: none"
        accept=".xml, .bpmn"
        @change="importLocalFile"
      />
    </div>
    <div class="pf-flow-design-canvas" ref="bpmnDom"></div>
    <flow-design-properties
      v-if="customPropertiesPanel"
      class="pf-flow-design-panel"
      id="js-properties-panel-custom"
    ></flow-design-properties>
    <div v-else class="pf-flow-design-panel" id="js-properties-panel"></div>
    <el-dialog
      title="预览"
      width="60%"
      v-model="previewModelVisible"
      append-to-body
      destroy-on-close
    >
      <highlightjs :language="previewType" :code="previewResult" />
    </el-dialog>
  </div>
</template>

<script lang="ts">
import { defineComponent, nextTick, onMounted, ref, Ref, toRefs, watch } from 'vue';
// 引入相关的依赖
// 以下为bpmn工作流绘图工具的样式
import 'bpmn-js/dist/assets/diagram-js.css'; // 左边工具栏以及编辑节点的样式
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css';
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css';
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';

import 'bpmn-js-properties-panel/dist/assets/properties-panel.css'; // 右边工具栏样式

import { initTemplate } from './default-flow';
import { modeler, ModelerEvents } from '@/views/page-config/flow/flow-modeler';
import FlowDesignProperties from '@/views/page-config/flow/custom-properties/FlowDesignProperties.vue';
import X2JS from 'x2js';
import { useNotice } from '@/components/element-plus/notice';

export default defineComponent({
  name: 'FlowDesign',
  components: { FlowDesignProperties },
  props: ['isCustomPanel', 'xml'],
  setup(props) {
    const customPropertiesPanel = toRefs(props).isCustomPanel;
    const flowXml = toRefs(props).xml;
    const bpmnDom: Ref = ref(null);
    const refFileDom: Ref = ref(null);

    // const container: any = null;
    const initDiagram = (xml?: string) => {
      modeler.getModeler().importXML(xml || initTemplate(), (err: any) => {
        if (err) {
          console.error(err);
        }
      });
    };

    const importLocalFile = () => {
      const file = refFileDom.value?.files[0];
      const reader = new FileReader();
      reader.readAsText(file);
      reader.onload = function (result) {
        if (result.target?.result && typeof result.target.result === 'string') {
          initDiagram(result.target.result);
        } else {
          console.error(result);
        }
      };
    };
    const setEncoded = (type: string, filename = 'diagram', data: string) => {
      const encodedData = encodeURIComponent(data);
      return {
        filename: `${filename}.${type}`,
        href: `data:application/${
          type === 'svg' ? 'text/xml' : 'bpmn20-xml'
        };charset=UTF-8,${encodedData}`,
        data: data
      };
    };
    const downloadFunc = (href: string, filename: string) => {
      if (href && filename) {
        const a = document.createElement('a');
        a.download = filename; //指定下载的文件名
        a.href = href; //  URL对象
        a.click(); // 模拟点击
        URL.revokeObjectURL(a.href); // 释放URL 对象
      }
    };
    const downloadProcess = async (type: string, name?: string) => {
      try {
        // 按需要类型创建文件并下载
        if (type === 'xml' || type === 'bpmn') {
          const { err, xml } = await modeler.getModeler().saveXML({ format: true });
          // 读取异常时抛出异常
          if (err) {
            useNotice().message.error(`[Process Designer Warn ]: ${err.message || err}`);
          } else {
            const { href, filename } = setEncoded(type.toUpperCase(), name, xml);
            downloadFunc(href, filename);
          }
        } else {
          const { err, svg } = await modeler.getModeler().saveSVG();
          // 读取异常时抛出异常
          if (err) {
            useNotice().message.error(`[Process Designer Warn ]: ${err.message || err}`);
          } else {
            const { href, filename } = setEncoded('SVG', name, svg);
            downloadFunc(href, filename);
          }
        }
      } catch (e: any) {
        console.error(`[Process Designer Warn ]: ${e.message || e}`);
      }
    };

    const previewModelVisible = ref(false);
    const previewResult = ref('');
    const previewType = ref('');
    const previewProcessJson = () => {
      const newConvert = new X2JS();
      modeler
        .getModeler()
        .saveXML({ format: true })
        .then((data: any) => {
          const { definitions } = newConvert.xml2js(data.xml);
          if (definitions) {
            previewResult.value = JSON.stringify(definitions, null, 4);
          } else {
            previewResult.value = '';
          }

          previewType.value = 'json';
          previewModelVisible.value = true;
        });
    };
    const previewProcessXML = () => {
      modeler
        .getModeler()
        .saveXML({ format: true })
        .then((data: any) => {
          previewResult.value = data.xml;
          previewType.value = 'xml';
          previewModelVisible.value = true;
        });
    };
    const revocable = ref(false);
    const recoverable = ref(false);
    const processRedo = () => {
      recoverable.value && modeler.getModeler().get('commandStack').redo();
    };
    const processUndo = () => {
      revocable.value && modeler.getModeler().get('commandStack').undo();
    };
    watch(
      flowXml,
      () => {
        initDiagram(flowXml.value);
      },
      { immediate: false }
    );
    onMounted(() => {
      nextTick(() => {
        modeler.init(bpmnDom.value, customPropertiesPanel.value);
        modeler.getEventBus().on(ModelerEvents.stackChanged, (event: any) => {
          recoverable.value = modeler.getModeler().get('commandStack').canRedo();
          revocable.value = modeler.getModeler().get('commandStack').canUndo();
        });
        initDiagram(flowXml.value);
      });
    });
    return {
      bpmnDom,
      refFileDom,
      customPropertiesPanel,
      downloadProcess,
      processRedo,
      processUndo,
      revocable,
      recoverable,
      previewModelVisible,
      previewType,
      previewResult,
      previewProcessXML,
      previewProcessJson,
      importLocalFile
    };
  }
});
</script>
<style scoped lang="scss">
.#{$prefix} {
  &-flow-design {
    //margin: 10px;
    //padding: 0;
    //overflow-y: auto;
    height: 70vh;
    &-op {
      position: absolute;
      z-index: 1;
    }
    &-canvas {
      height: 70vh;
    }
    &-panel {
      position: absolute;
      height: calc(70vh - 130px);
      width: 30%;
      top: 130px;
      right: 10px;
      overflow-y: auto;
      background: #f0f2f5;
      border: 2px solid darkred;
      border-radius: 5px;
      //height: 100%;
    }
  }
}
</style>
